f[3] = c->alpha;
}
+static inline gboolean
+node_is_invisible (const GskRenderNode *node)
+{
+ return node->bounds.size.width == 0.0f ||
+ node->bounds.size.height == 0.0f ||
+ isnan (node->bounds.size.width) ||
+ isnan (node->bounds.size.height);
+}
+
static inline void
sort_border_sides (const GdkRGBA *colors,
int *indices)
static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
-static void add_offscreen_ops (GskGLRenderer *self,
+static gboolean add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *bounds,
GskRenderNode *child_node,
TextureRegion *region_out,
gboolean *is_offscreen,
- guint flags);
+ guint flags) G_GNUC_WARN_UNUSED_RESULT;
static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder);
}
else
{
- const float min_x = child->bounds.origin.x;
- const float min_y = child->bounds.origin.y;
- const float max_x = min_x + child->bounds.size.width;
- const float max_y = min_y + child->bounds.size.height;
TextureRegion region;
gboolean is_offscreen;
/* For non-trivial transforms, we draw everything on a texture and then
* part (e.g. the rotation) and use that. We want to keep the scale
* for the texture.
*/
- add_offscreen_ops (self, builder,
- &child->bounds,
- child,
- ®ion, &is_offscreen,
- RESET_CLIP | RESET_OPACITY);
-
- ops_push_modelview (builder, node_transform);
- ops_set_texture (builder, region.texture_id);
- ops_set_program (builder, &self->blit_program);
-
- if (is_offscreen)
+ if (add_offscreen_ops (self, builder,
+ &child->bounds,
+ child,
+ ®ion, &is_offscreen,
+ RESET_CLIP | RESET_OPACITY))
{
- const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
- { { min_x, min_y }, { region.x, region.y2 }, },
- { { min_x, max_y }, { region.x, region.y }, },
- { { max_x, min_y }, { region.x2, region.y2 }, },
-
- { { max_x, max_y }, { region.x2, region.y }, },
- { { min_x, max_y }, { region.x, region.y }, },
- { { max_x, min_y }, { region.x2, region.y2 }, },
- };
-
- ops_draw (builder, offscreen_vertex_data);
- }
- else
- {
- const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
- { { min_x, min_y }, { region.x, region.y }, },
- { { min_x, max_y }, { region.x, region.y2 }, },
- { { max_x, min_y }, { region.x2, region.y }, },
-
- { { max_x, max_y }, { region.x2, region.y2 }, },
- { { min_x, max_y }, { region.x, region.y2 }, },
- { { max_x, min_y }, { region.x2, region.y }, },
- };
-
- ops_draw (builder, onscreen_vertex_data);
+ const float min_x = child->bounds.origin.x;
+ const float min_y = child->bounds.origin.y;
+ const float max_x = min_x + child->bounds.size.width;
+ const float max_y = min_y + child->bounds.size.height;
+
+ ops_push_modelview (builder, node_transform);
+ ops_set_texture (builder, region.texture_id);
+ ops_set_program (builder, &self->blit_program);
+
+ if (is_offscreen)
+ {
+ const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
+ { { min_x, min_y }, { region.x, region.y2 }, },
+ { { min_x, max_y }, { region.x, region.y }, },
+ { { max_x, min_y }, { region.x2, region.y2 }, },
+
+ { { max_x, max_y }, { region.x2, region.y }, },
+ { { min_x, max_y }, { region.x, region.y }, },
+ { { max_x, min_y }, { region.x2, region.y2 }, },
+ };
+
+ ops_draw (builder, offscreen_vertex_data);
+ }
+ else
+ {
+ const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
+ { { min_x, min_y }, { region.x, region.y }, },
+ { { min_x, max_y }, { region.x, region.y2 }, },
+ { { max_x, min_y }, { region.x2, region.y }, },
+
+ { { max_x, max_y }, { region.x2, region.y2 }, },
+ { { min_x, max_y }, { region.x, region.y2 }, },
+ { { max_x, min_y }, { region.x2, region.y }, },
+ };
+
+ ops_draw (builder, onscreen_vertex_data);
+ }
}
ops_pop_modelview (builder);
/* The semantics of an opacity node mandate that when, e.g., two color nodes overlap,
* there may not be any blending between them */
- add_offscreen_ops (self, builder, &child->bounds,
- child,
- ®ion, &is_offscreen,
- FORCE_OFFSCREEN | RESET_OPACITY | RESET_CLIP);
+ if (!add_offscreen_ops (self, builder, &child->bounds,
+ child,
+ ®ion, &is_offscreen,
+ FORCE_OFFSCREEN | RESET_OPACITY | RESET_CLIP))
+ return;
prev_opacity = ops_set_opacity (builder,
builder->current_opacity * opacity);
gboolean need_offscreen;
int i;
+ if (node_is_invisible (child))
+ return;
+
transformed_clip = child_clip;
ops_transform_bounds_modelview (builder, &child_clip.bounds, &transformed_clip.bounds);
}
ops_push_clip (builder, &child_clip);
- add_offscreen_ops (self, builder, &node->bounds,
- child,
- ®ion, &is_offscreen,
- FORCE_OFFSCREEN | RESET_OPACITY);
+ g_assert (add_offscreen_ops (self, builder, &node->bounds,
+ child,
+ ®ion, &is_offscreen,
+ FORCE_OFFSCREEN | RESET_OPACITY));
ops_pop_clip (builder);
ops_set_program (builder, &self->blit_program);
TextureRegion region;
gboolean is_offscreen;
- add_offscreen_ops (self, builder,
- &node->bounds,
- child,
- ®ion, &is_offscreen,
- RESET_CLIP | RESET_OPACITY);
+ if (node_is_invisible (child))
+ return;
+
+ g_assert (add_offscreen_ops (self, builder,
+ &node->bounds,
+ child,
+ ®ion, &is_offscreen,
+ RESET_CLIP | RESET_OPACITY));
ops_set_program (builder, &self->color_matrix_program);
ops_set_color_matrix (builder,
return;
}
+ if (node_is_invisible (child))
+ return;
+
/* TODO(perf): We're forcing the child offscreen even if it's a texture
* so the resulting offscreen texture is bigger by the gaussian blur factor
* (see gsk_blur_node_new), but we didn't have to do that if the blur
* shader could handle that situation. */
- add_offscreen_ops (self, builder,
- &node->bounds,
- child,
- ®ion, &is_offscreen,
- RESET_CLIP | FORCE_OFFSCREEN | RESET_OPACITY);
+ g_assert (add_offscreen_ops (self, builder,
+ &node->bounds,
+ child,
+ ®ion, &is_offscreen,
+ RESET_CLIP | FORCE_OFFSCREEN | RESET_OPACITY));
ops_set_program (builder, &self->blur_program);
if (gdk_rgba_is_clear (&shadow->color))
continue;
+ if (node_is_invisible (shadow_child))
+ continue;
+
/* Draw the child offscreen, without the offset. */
- add_offscreen_ops (self, builder,
- &shadow_child->bounds,
- shadow_child, ®ion, &is_offscreen,
- RESET_CLIP | RESET_OPACITY);
+ g_assert (add_offscreen_ops (self, builder,
+ &shadow_child->bounds,
+ shadow_child, ®ion, &is_offscreen,
+ RESET_CLIP | RESET_OPACITY));
ops_set_program (builder, &self->coloring_program);
ops_set_color (builder, &shadow->color);
/* TODO: We create 2 textures here as big as the cross-fade node, but both the
* start and the end node might be a lot smaller than that. */
- add_offscreen_ops (self, builder,
- &node->bounds,
- start_node,
- &start_region, &is_offscreen1,
- FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY);
+ g_assert (add_offscreen_ops (self, builder,
+ &node->bounds,
+ start_node,
+ &start_region, &is_offscreen1,
+ FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY));
- add_offscreen_ops (self, builder,
- &node->bounds,
- end_node,
- &end_region, &is_offscreen2,
- FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY);
+ g_assert (add_offscreen_ops (self, builder,
+ &node->bounds,
+ end_node,
+ &end_region, &is_offscreen2,
+ FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY));
ops_set_program (builder, &self->cross_fade_program);
/* TODO: We create 2 textures here as big as the blend node, but both the
* start and the end node might be a lot smaller than that. */
- add_offscreen_ops (self, builder,
- &node->bounds,
- bottom_child,
- &bottom_region, &is_offscreen1,
- FORCE_OFFSCREEN | RESET_CLIP);
-
- add_offscreen_ops (self, builder,
- &node->bounds,
- top_child,
- &top_region, &is_offscreen2,
- FORCE_OFFSCREEN | RESET_CLIP);
+ g_assert (add_offscreen_ops (self, builder,
+ &node->bounds,
+ bottom_child,
+ &bottom_region, &is_offscreen1,
+ FORCE_OFFSCREEN | RESET_CLIP));
+
+ g_assert (add_offscreen_ops (self, builder,
+ &node->bounds,
+ top_child,
+ &top_region, &is_offscreen2,
+ FORCE_OFFSCREEN | RESET_CLIP));
ops_set_program (builder, &self->blend_program);
ops_set_texture (builder, bottom_region.texture_id);
gboolean is_offscreen;
OpRepeat *op;
+ if (node_is_invisible (child))
+ return;
+
if (child_bounds != NULL &&
!graphene_rect_equal (child_bounds, &child->bounds))
{
}
/* Draw the entire child on a texture */
- add_offscreen_ops (self, builder,
- &child->bounds,
- child,
- ®ion, &is_offscreen,
- RESET_CLIP | RESET_OPACITY);
+ g_assert (add_offscreen_ops (self, builder,
+ &child->bounds,
+ child,
+ ®ion, &is_offscreen,
+ RESET_CLIP | RESET_OPACITY | DUMP_FRAMEBUFFER| FORCE_OFFSCREEN));
ops_set_program (builder, &self->repeat_program);
ops_set_texture (builder, region.texture_id);
/* This can still happen, even if the render nodes are created using
* GtkSnapshot, so let's juse be safe. */
- if (node->bounds.size.width == 0.0f || node->bounds.size.height == 0.0f ||
- isnan (node->bounds.size.width) || isnan (node->bounds.size.height))
+ if (node_is_invisible (node))
return;
/* Check whether the render node is entirely out of the current
}
}
-static void
+static gboolean
add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *bounds,
float prev_opacity;
int texture_id = 0;
+ if (node_is_invisible (child_node))
+ {
+ /* Just to be safe */
+ *is_offscreen = FALSE;
+ init_full_texture_region (texture_region_out, 0);
+ return FALSE;
+ }
+
/* We need the child node as a texture. If it already is one, we don't need to draw
* it on a framebuffer of course. */
if (gsk_render_node_get_node_type (child_node) == GSK_TEXTURE_NODE &&
upload_texture (self, texture, texture_region_out);
*is_offscreen = FALSE;
- return;
+ return TRUE;
}
/* Check if we've already cached the drawn texture. */
init_full_texture_region (texture_region_out, cached_id);
/* We didn't render it offscreen, but hand out an offscreen texture id */
*is_offscreen = TRUE;
- return;
+ return TRUE;
}
}
init_full_texture_region (texture_region_out, texture_id);
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id);
+
+ return TRUE;
}
static void